/*
* Sun Public License Notice
*
* The contents of this file are subject to the Sun Public License
* Version 1.0 (the "License"). You may not use this file except in
* compliance with the License. A copy of the License is available at
* http://www.sun.com/
*
* The Original Code is Forte for Java, Community Edition. The Initial
* Developer of the Original Code is Sun Microsystems, Inc. Portions
* Copyright 1997-2000 Sun Microsystems, Inc. All Rights Reserved.
*/
package org.netbeans.editor;
import java.awt.event.ActionEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import javax.swing.Action;
import javax.swing.text.BadLocationException;
import javax.swing.text.JTextComponent;
import javax.swing.text.Caret;
/** Abbreviation support allowing to expand defined character sequences
* into the expanded strings or call the arbitrary action.
*
* @author Miloslav Metelka
* @version 1.00
*/
public class Abbrev implements SettingsChangeListener, PropertyChangeListener {
/** Abbreviation accounting string. Here the characters forming
* abbreviation are stored.
*/
private StringBuffer abbrevSB = new StringBuffer();
/** Check whether the document text matches the abbreviation accounting
* string.
*/
private boolean checkDocText;
/** Additional check whether the character right before the abbreviation
* string in the text is not accepted by the <tt>addTypedAcceptor</tt>.
* This test is only performed if <tt>checkDocText</tt> is true.
*/
private boolean checkTextDelimiter;
/** Extended UI to which this abbreviation is associated to */
protected ExtUI extUI;
/** Chars on which to expand acceptor */
private Acceptor doExpandAcceptor;
/** Whether add the typed char */
private Acceptor addTypedAcceptor;
/** Which chars reset abbreviation accounting */
private Acceptor resetAcceptor;
/** Abbreviation map */
private HashMap abbrevMap;
public Abbrev(ExtUI extUI, boolean checkDocText, boolean checkTextDelimiter) {
this.extUI = extUI;
this.checkDocText = checkDocText;
this.checkTextDelimiter = checkTextDelimiter;
Settings.addSettingsChangeListener(this);
extUI.addPropertyChangeListener(this);
settingsChange(null);
}
/** Called when settings were changed. The method is called
* by extUI when settings were changed and from constructor.
*/
public void settingsChange(SettingsChangeEvent evt) {
Class kitClass = Utilities.getKitClass(extUI.getComponent());
if (kitClass != null) {
String settingName = (evt != null) ? evt.getSettingName() : null;
if (settingName == null || Settings.ABBREV_ACTION_MAP.equals(settingName)) {
abbrevMap = new HashMap();
// Inspect action abbrevs
Map m = (Map)Settings.getValue(kitClass, Settings.ABBREV_ACTION_MAP);
if (m != null) {
BaseKit kit = Utilities.getKit(extUI.getComponent());
Iterator iter = m.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry me = (Map.Entry)iter.next();
Object value = me.getValue();
Action a = null;
if (value instanceof String) {
a = kit.getActionByName((String)value);
} else if (value instanceof Action) {
a = (Action)value;
}
if (a != null) {
abbrevMap.put(me.getKey(), a);
}
}
}
}
if (settingName == null || Settings.ABBREV_MAP.equals(settingName)) {
// Inspect string abbrevs
Map m = (Map)Settings.getValue(kitClass, Settings.ABBREV_MAP);
if (m != null) {
Iterator iter = m.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry me = (Map.Entry)iter.next();
Object value = me.getValue();
if (value != null) {
abbrevMap.put(me.getKey(), value);
}
}
}
}
if (settingName == null || Settings.ABBREV_EXPAND_ACCEPTOR.equals(settingName)) {
doExpandAcceptor = SettingsUtil.getAcceptor(kitClass, Settings.ABBREV_EXPAND_ACCEPTOR, AcceptorFactory.FALSE);
}
if (settingName == null || Settings.ABBREV_ADD_TYPED_CHAR_ACCEPTOR.equals(settingName)) {
addTypedAcceptor = SettingsUtil.getAcceptor(kitClass, Settings.ABBREV_ADD_TYPED_CHAR_ACCEPTOR, AcceptorFactory.FALSE);
}
if (settingName == null || Settings.ABBREV_RESET_ACCEPTOR.equals(settingName)) {
resetAcceptor = SettingsUtil.getAcceptor(kitClass, Settings.ABBREV_RESET_ACCEPTOR, AcceptorFactory.TRUE);
}
}
}
public void propertyChange(PropertyChangeEvent evt) {
String propName = evt.getPropertyName();
if (ExtUI.COMPONENT_PROPERTY.equals(propName)) {
if (evt.getNewValue() != null) { // just installed
JTextComponent c = extUI.getComponent();
settingsChange(null);
} else { // just deinstalled
JTextComponent c = (JTextComponent)evt.getOldValue();
}
}
}
/** Reset abbreviation accounting. */
public void reset() {
abbrevSB.setLength(0);
}
/** Add typed character to abbreviation accounting string. */
public void addChar(char ch) {
abbrevSB.append(ch);
}
/** Get current abbreviation string */
public String getAbbrevString() {
return abbrevSB.toString();
}
/** Get mapping table [abbrev, expanded-abbrev] */
public Map getAbbrevMap() {
return abbrevMap;
}
/** Translate string using abbreviation table
* @param abbrev string to translate. Pass null to translate current abbreviation
* string
* @return expanded abbreviation
*/
public Object translateAbbrev(String abbrev) {
String abbStr = (abbrev != null) ? abbrev : abbrevSB.toString();
return getAbbrevMap().get(abbStr);
}
/** Checks whether there's valid string to expand and if so it returns it.
*/
public String getExpandString(char typedChar) {
return (doExpandAcceptor.accept(typedChar)) ? getExpandString() : null;
}
public String getExpandString() {
BaseDocument doc = (BaseDocument)extUI.getDocument();
String abbrevStr = getAbbrevString();
int abbrevStrLen = abbrevStr.length();
Object expansion = translateAbbrev(abbrevStr);
Caret caret = extUI.getComponent().getCaret();
int dotPos = caret.getDot();
if (abbrevStr != null && expansion != null
&& dotPos >= abbrevStrLen
) {
if (checkDocText) {
try {
String prevChars = doc.getText(dotPos - abbrevStrLen, abbrevStrLen);
if (prevChars.equals(abbrevStr)) { // abbrev chars really match text
if (!checkTextDelimiter || dotPos == abbrevStrLen
|| resetAcceptor.accept(
doc.getChars(dotPos - abbrevStrLen - 1, 1)[0])
) {
return abbrevStr;
}
}
} catch (BadLocationException e) {
}
}
}
return null;
}
protected boolean doExpansion(int dotPos, String expandStr, ActionEvent evt)
throws BadLocationException {
Object expansion = translateAbbrev(expandStr);
boolean expanded = false;
if (expansion instanceof String) { // expand to string
BaseDocument doc = extUI.getDocument();
doc.insertString(dotPos, (String)expansion, null);
expanded = true;
} else if (expansion instanceof Action) {
((Action)expansion).actionPerformed(evt);
expanded = true;
}
return expanded;
}
public boolean expandString(char typedChar, String expandStr, ActionEvent evt)
throws BadLocationException {
if (expandString(expandStr, evt)) {
if (addTypedAcceptor.accept(typedChar)) {
int dotPos = extUI.getComponent().getCaret().getDot();
extUI.getDocument().insertString(dotPos, String.valueOf(typedChar), null);
}
return true;
}
return false;
}
/** Expand abbreviation on current caret position.
* Remove characters back to the word start and insert expanded abbreviation.
* @return whether the typed character should be added to the abbreviation or not
*/
public boolean expandString(String expandStr, ActionEvent evt)
throws BadLocationException {
boolean expanded = false;
BaseDocument doc = extUI.getDocument();
doc.atomicLock();
try {
Caret caret = extUI.getComponent().getCaret();
int pos = caret.getDot() - expandStr.length();
if (expandStr != null) {
doc.remove(pos, expandStr.length());
expanded = doExpansion(pos, expandStr, evt);
}
} finally {
if (expanded) {
reset();
} else {
doc.breakAtomicLock();
}
doc.atomicUnlock();
}
return expanded;
}
public boolean checkReset(char typedChar) {
if (resetAcceptor.accept(typedChar)) {
reset();
return true;
}
return false;
}
public boolean checkAndExpand(char typedChar, ActionEvent evt)
throws BadLocationException {
boolean doInsert = true;
String expandStr = getExpandString(typedChar);
if (expandStr != null) { // should expand
doInsert = false;
expandString(typedChar, expandStr, evt);
} else {
addChar(typedChar);
}
checkReset(typedChar);
return doInsert;
}
public void checkAndExpand(ActionEvent evt)
throws BadLocationException {
String expandStr = getExpandString();
if (expandStr != null) {
expandString(expandStr, evt);
}
}
}
/*
* Log
* 14 Gandalf-post-FCS1.12.1.0 3/8/00 Miloslav Metelka
* 13 Gandalf 1.12 1/13/00 Miloslav Metelka
* 12 Gandalf 1.11 1/4/00 Miloslav Metelka
* 11 Gandalf 1.10 11/9/99 Miloslav Metelka
* 10 Gandalf 1.9 10/23/99 Ian Formanek NO SEMANTIC CHANGE - Sun
* Microsystems Copyright in File Comment
* 9 Gandalf 1.8 9/16/99 Miloslav Metelka
* 8 Gandalf 1.7 8/17/99 Miloslav Metelka
* 7 Gandalf 1.6 7/20/99 Miloslav Metelka
* 6 Gandalf 1.5 6/22/99 Miloslav Metelka
* 5 Gandalf 1.4 6/10/99 Miloslav Metelka
* 4 Gandalf 1.3 6/1/99 Miloslav Metelka
* 3 Gandalf 1.2 5/15/99 Miloslav Metelka fixes
* 2 Gandalf 1.1 5/5/99 Miloslav Metelka
* 1 Gandalf 1.0 4/23/99 Miloslav Metelka
* $
*/